using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using JGSY.CMS.LowCode.Platform.Application.DTOs;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;
using System.Security.Cryptography;
using System.Text.Json;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;

namespace JGSY.CMS.LowCode.Platform.Application.Services
{
    /// <summary>
    /// 媒体文件应用服务实现
    /// </summary>
    public class MediaFileAppService : IMediaFileAppService
    {
        private readonly IMediaFileRepository _mediaFileRepository;
        private readonly ILogger<MediaFileAppService> _logger;
        private readonly ICloudStorageService _storageService;
        private readonly string[] _allowedImageTypes = { "image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp" };
        private readonly string[] _allowedVideoTypes = { "video/mp4", "video/avi", "video/mov", "video/wmv", "video/flv" };
        private readonly string[] _allowedDocumentTypes = { "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "text/plain" };
        private const long MaxFileSize = 100 * 1024 * 1024; // 100MB

        public MediaFileAppService(
            IMediaFileRepository mediaFileRepository,
            ILogger<MediaFileAppService> logger,
            ICloudStorageService storageService)
        {
            _mediaFileRepository = mediaFileRepository;
            _logger = logger;
            _storageService = storageService;
        }
        public async Task<int> BatchDeleteAsync(IEnumerable<long> ids, bool deletePhysicalFiles = true)
        {
            var deletedCount = 0;
            
            foreach (var id in ids)
            {
                try
                {
                    if (await DeleteAsync(id, deletePhysicalFiles))
                    {
                        deletedCount++;
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error deleting file in batch: {Id}", id);
                }
            }
            
            return deletedCount;
        }

        public async Task<IEnumerable<MediaFileDto>> BatchUploadAsync(IEnumerable<IFormFile> files, string? category = null)
        {
            var results = new List<MediaFileDto>();
            
            foreach (var file in files)
            {
                try
                {
                    var result = await UploadAsync(file, category);
                    results.Add(result);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error uploading file in batch: {FileName}", file.FileName);
                    // 继续处理其他文件，不中断批量上传
                }
            }
            
            return results;
        }

        public async Task<int> CleanupUnusedFilesAsync()
        {
            try
            {
                // 获取所有状态为临时文件（0）且创建时间超过24小时的文件
                var cutoffTime = DateTime.UtcNow.AddDays(-1);
                var allFiles = await _mediaFileRepository.GetAllAsync();
                var unusedFiles = allFiles.Where(f => 
                    f.Status == 0 && // 临时文件状态
                    f.CreatedAt < cutoffTime &&
                    f.UsedCount == 0
                ).ToList();

                var cleanedCount = 0;
                foreach (var file in unusedFiles)
                {
                    try
                    {
                        // 删除物理文件和数据库记录
                        if (await DeleteAsync(file.Id, true))
                        {
                            cleanedCount++;
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Error cleaning up unused file: {Id}", file.Id);
                    }
                }

                _logger.LogInformation("Cleaned up {Count} unused media files", cleanedCount);
                return cleanedCount;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error during cleanup of unused files");
                return 0;
            }
        }

        public async Task<MediaFileDto> CreateAsync(MediaFileDto mediaFileDto)
        {
            var entity = new MediaFile
            {
                Name = mediaFileDto.FileName,
                Type = mediaFileDto.FileType,
                Url = mediaFileDto.FileUrl ?? string.Empty,
                Size = mediaFileDto.FileSize,
                ThumbnailUrl = mediaFileDto.ThumbnailUrl,
                MimeType = mediaFileDto.MimeType,
                Md5Hash = mediaFileDto.Hash,
                Description = mediaFileDto.Description,
                OriginalName = mediaFileDto.OriginalFileName,
                StoragePath = mediaFileDto.FilePath,
                Width = mediaFileDto.Width,
                Height = mediaFileDto.Height,
                Duration = mediaFileDto.Duration,
                Status = mediaFileDto.Status,
                IsPublic = mediaFileDto.IsPublic,
                CreatedBy = mediaFileDto.CreatedBy,
                CreatedAt = DateTime.UtcNow
            };

            await _mediaFileRepository.AddAsync(entity);
            return MapToDto(entity);
        }

        public async Task<bool> DeleteAsync(long id, bool deletePhysicalFile = true)
        {
            try
            {
                var entity = await _mediaFileRepository.GetByIdAsync(id);
                if (entity == null)
                    return false;

                // 如果需要删除物理文件
                if (deletePhysicalFile && !string.IsNullOrEmpty(entity.StoragePath))
                {
                    // 可以调用存储服务删除文件
                    // await _storageService.DeleteAsync(entity.StoragePath);
                }

                await _mediaFileRepository.DeleteAsync(id);
                _logger.LogInformation("Media file deleted: {Id}", id);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting media file: {Id}", id);
                return false;
            }
        }

        public async Task<string?> GenerateThumbnailAsync(long id, int width = 150, int height = 150)
        {
            try
            {
                var entity = await _mediaFileRepository.GetByIdAsync(id);
                if (entity == null || !IsImageFile(entity.MimeType ?? string.Empty))
                    return null;

                // 如果已经有缩略图，直接返回
                if (!string.IsNullOrEmpty(entity.ThumbnailUrl))
                    return entity.ThumbnailUrl;

                // 简化实现：使用原图作为缩略图
                // 在实际项目中，可以使用ImageSharp生成缩略图并上传到存储服务
                entity.ThumbnailUrl = entity.Url;
                await _mediaFileRepository.UpdateAsync(entity);
                
                return entity.ThumbnailUrl;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error generating thumbnail for media file: {Id}", id);
                return null;
            }
        }

        public async Task<IEnumerable<MediaFileDto>> GetAllAsync()
        {
            var entities = await _mediaFileRepository.GetAllAsync();
            return entities.Select(MapToDto);
        }

        public async Task<IEnumerable<MediaFileDto>> GetByCategoryAsync(string category)
        {
            var entities = await _mediaFileRepository.GetByCategoryAsync(category);
            return entities.Select(MapToDto);
        }

        public async Task<MediaFileDto?> GetByFilePathAsync(string filePath)
        {
            var entity = await _mediaFileRepository.GetByFilePathAsync(filePath);
            return entity == null ? null : MapToDto(entity);
        }

        public async Task<IEnumerable<MediaFileDto>> GetByFileTypeAsync(string fileType)
        {
            var entities = await _mediaFileRepository.GetByFileTypeAsync(fileType);
            return entities.Select(MapToDto);
        }

        public async Task<MediaFileDto?> GetByHashAsync(string hash)
        {
            var entity = await _mediaFileRepository.GetByHashAsync(hash);
            return entity == null ? null : MapToDto(entity);
        }

        public async Task<MediaFileDto?> GetByIdAsync(long id)
        {
            var entity = await _mediaFileRepository.GetByIdAsync(id);
            return entity == null ? null : MapToDto(entity);
        }

        public async Task<string?> GetFileUrlAsync(long id, int? expireMinutes = null)
        {
            var entity = await _mediaFileRepository.GetByIdAsync(id);
            if (entity == null)
                return null;

            // 如果是公开文件，直接返回URL
            if (entity.IsPublic)
                return entity.Url;

            // 对于私有文件，可以通过存储服务生成临时URL
            // return await _storageService.GeneratePresignedUrlAsync(entity.StoragePath, expireMinutes ?? 60);
            
            // 简单实现：返回原始URL
            return entity.Url;
        }

        public async Task<(IEnumerable<MediaFileDto> Items, int TotalCount)> GetPagedAsync(int pageIndex, int pageSize, string? keyword = null, string? category = null, string? fileType = null, byte? status = null)
        {
            var (items, totalCount) = await _mediaFileRepository.GetPagedAsync(pageIndex, pageSize, keyword, category, fileType, status);
            var dtos = items.Select(MapToDto).ToList();
            return (dtos, totalCount);
        }

        public async Task<object> GetStorageStatisticsAsync()
        {
            try
            {
                var allFiles = await _mediaFileRepository.GetAllAsync();
                var totalFiles = allFiles.Count();
                var totalSize = allFiles.Sum(f => f.Size);
                
                var imageCount = allFiles.Count(f => f.Type == "image");
                var videoCount = allFiles.Count(f => f.Type == "video");
                var documentCount = allFiles.Count(f => f.Type == "document");
                
                return new
                {
                    TotalFiles = totalFiles,
                    TotalSize = totalSize,
                    TotalSizeFormatted = $"{totalSize / (1024.0 * 1024.0):F2} MB",
                    FileTypeCounts = new
                    {
                        Images = imageCount,
                        Videos = videoCount,
                        Documents = documentCount,
                        Others = totalFiles - imageCount - videoCount - documentCount
                    }
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting storage statistics");
                throw;
            }
        }

        public async Task<bool> IncrementDownloadCountAsync(long id)
        {
            try
            {
                var entity = await _mediaFileRepository.GetByIdAsync(id);
                if (entity == null)
                    return false;

                entity.DownloadCount++;
                await _mediaFileRepository.UpdateAsync(entity);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error incrementing download count: {Id}", id);
                return false;
            }
        }

        public async Task<(IEnumerable<MediaFileDto> Items, int TotalCount)> SearchAsync(string keyword, int pageIndex = 1, int pageSize = 20)
        {
            var (items, totalCount) = await _mediaFileRepository.SearchAsync(keyword, pageIndex, pageSize);
            var dtos = items.Select(MapToDto).ToList();
            return (dtos, totalCount);
        }

        public async Task<MediaFileDto> UpdateAsync(MediaFileDto mediaFileDto)
        {
            var entity = await _mediaFileRepository.GetByIdAsync(mediaFileDto.Id);
            if (entity == null)
                throw new ArgumentException($"MediaFile with ID {mediaFileDto.Id} not found");

            // 更新实体属性
            entity.Name = mediaFileDto.FileName;
            entity.Description = mediaFileDto.Description;
            entity.IsPublic = mediaFileDto.IsPublic;
            entity.Status = mediaFileDto.Status;

            await _mediaFileRepository.UpdateAsync(entity);
            return MapToDto(entity);
        }

        public async Task<bool> UpdateStatusAsync(long id, byte status)
        {
            try
            {
                var entity = await _mediaFileRepository.GetByIdAsync(id);
                if (entity == null)
                    return false;

                entity.Status = status;
                await _mediaFileRepository.UpdateAsync(entity);
                
                _logger.LogInformation("Media file status updated: {Id}, Status: {Status}", id, status);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating media file status: {Id}", id);
                return false;
            }
        }

        public async Task<MediaFileDto> UploadAsync(IFormFile file, string? category = null, string? title = null, string? description = null, string? alt = null)
        {
            try
            {
                // 验证文件
                if (!await ValidateFileAsync(file))
                {
                    throw new ArgumentException("无效的文件或文件类型不被支持");
                }

                // 计算文件哈希
                var fileHash = await ComputeFileHashAsync(file);
                
                // 检查是否已存在相同文件
                var existingFile = await _mediaFileRepository.GetByHashAsync(fileHash);
                if (existingFile != null)
                {
                    _logger.LogInformation("File already exists: {Hash}", fileHash);
                    return MapToDto(existingFile);
                }

                // 生成文件名和路径
                var fileName = GenerateFileName(file.FileName);
                var folderPath = category ?? "uploads";

                // 上传文件到存储服务
                var fileUrl = await _storageService.UploadAsync(file, folderPath);

                // 获取图片尺寸（如果是图片）
                int? width = null, height = null;
                if (IsImageFile(file.ContentType))
                {
                    (width, height) = await GetImageDimensionsAsync(file);
                }

                // 创建MediaFile实体
                var mediaFile = new MediaFile
                {
                    Name = title ?? Path.GetFileNameWithoutExtension(file.FileName),
                    Type = GetFileType(file.ContentType),
                    Url = fileUrl,
                    Size = file.Length,
                    ThumbnailUrl = null, // 可以后续生成缩略图
                    MimeType = file.ContentType,
                    Md5Hash = fileHash,
                    Description = description,
                    OriginalName = file.FileName,
                    StoragePath = $"{folderPath}/{fileName}",
                    Extension = Path.GetExtension(file.FileName),
                    Width = width,
                    Height = height,
                    Status = 1, // 启用状态
                    DownloadCount = 0,
                    ViewCount = 0,
                    UsedCount = 0,
                    IsPublic = true,
                    CreatedBy = 1, // 需要从当前用户上下文获取
                    CreatedAt = DateTime.UtcNow
                };

                await _mediaFileRepository.AddAsync(mediaFile);
                _logger.LogInformation("Media file uploaded successfully: {FileName}", fileName);

                return MapToDto(mediaFile);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error uploading media file: {FileName}", file?.FileName);
                throw;
            }
        }

        public Task<bool> ValidateFileAsync(IFormFile file, string[]? allowedTypes = null)
        {
            if (file == null || file.Length == 0)
                return Task.FromResult(false);

            if (file.Length > MaxFileSize)
                return Task.FromResult(false);

            var allowedMimeTypes = allowedTypes ?? 
                _allowedImageTypes.Concat(_allowedVideoTypes).Concat(_allowedDocumentTypes).ToArray();

            return Task.FromResult(allowedMimeTypes.Contains(file.ContentType.ToLower()));
        }

        // 私有辅助方法
        private async Task<string> ComputeFileHashAsync(IFormFile file)
        {
            using var md5 = MD5.Create();
            using var stream = file.OpenReadStream();
            var hash = await Task.Run(() => md5.ComputeHash(stream));
            return Convert.ToBase64String(hash);
        }

        private string GenerateFileName(string originalFileName)
        {
            var extension = Path.GetExtension(originalFileName);
            return $"{Guid.NewGuid()}{extension}";
        }

        private bool IsImageFile(string mimeType)
        {
            return _allowedImageTypes.Contains(mimeType?.ToLower());
        }

        private async Task<(int? width, int? height)> GetImageDimensionsAsync(IFormFile file)
        {
            try
            {
                using var stream = file.OpenReadStream();
                using var image = await Image.LoadAsync(stream);
                return (image.Width, image.Height);
            }
            catch
            {
                return (null, null);
            }
        }

        private string GetFileType(string mimeType)
        {
            if (_allowedImageTypes.Contains(mimeType?.ToLower()))
                return "image";
            if (_allowedVideoTypes.Contains(mimeType?.ToLower()))
                return "video";
            if (_allowedDocumentTypes.Contains(mimeType?.ToLower()))
                return "document";
            return "other";
        }

        private MediaFileDto MapToDto(MediaFile entity)
        {
            return new MediaFileDto
            {
                Id = entity.Id,
                FileName = entity.Name ?? string.Empty,
                FileType = entity.Type ?? "other",
                FileUrl = entity.Url,
                FileSize = entity.Size,
                ThumbnailUrl = entity.ThumbnailUrl,
                MimeType = entity.MimeType,
                Hash = entity.Md5Hash,
                Description = entity.Description,
                OriginalFileName = entity.OriginalName,
                FilePath = entity.StoragePath ?? string.Empty,
                Width = entity.Width,
                Height = entity.Height,
                Duration = entity.Duration,
                Status = entity.Status,
                DownloadCount = entity.DownloadCount,
                IsPublic = entity.IsPublic,
                CreatedBy = entity.CreatedBy,
                CreatedAt = entity.CreatedAt,
                UpdatedAt = entity.CreatedAt // 使用创建时间作为更新时间
            };
        }
    }
}
